#ifndef __MVS_MQTT_H__
#define __MVS_MQTT_H__

#include "mvdef.h"

MVCXX_EXTERN_BEGIN

/**
 * @brief 当前支持协议版本
 * 
 */
#define MQTT_PROTOCOL_V3_1    3
#define MQTT_PROTOCOL_V3_1_1  4
#define MQTT_PROTOCOL_V5      5 ///< 暂未完整支持
/**
 * @brief MQTT 协议版本选择
 * 
 */
#define MQTT_PROTOCOL_VER_SUPPORT  MQTT_PROTOCOL_V5 ///< 向下兼容

/***************************************************/
typedef enum _connect_result
{
    MQTT_CONNECT_ACCEPTED          = 0, ///< 连接正常成功
    MQTT_CONNECT_REFUSED           = 1, ///< 连接拒绝
    MQTT_CONNECT_SESSION_UNWILLING = 2, ///< session不符合预期
}mvs_mqtt_connect_result_e;

/** V3.X 协议版本connack响应码 */
typedef enum _connection_return_code_v3
{
    MQTT_CONNECTION_ACCEPTED                        = 0x00,
    MQTT_CONNECTION_V3_REFUSED_PVER                 = 0x01, ///< UNACCEPTABLE_PROTOCOL_VERSION (不支持的协议版本)
    MQTT_CONNECTION_V3_REFUSED_CID                  = 0x02, ///< IDENTIFIER REJECTED (客户端标识被拒)
    MQTT_CONNECTION_V3_REFUSED_BAD_SVR              = 0x03, ///< SERVER UNAVAILABLE (服务器不可用)
    MQTT_CONNECTION_V3_REFUSED_ACCOUNT              = 0x04, ///< BAD USER NAME OR PASSWORD (用户名或密码错误)
    MQTT_CONNECTION_V3_REFUSED_NOT_AUTH             = 0x05, ///< NOT AUTHORIZED (无鉴权信息)
}mqtt_connack_code_v3_e;

/** V5.X 协议版本connack响应码 */
typedef enum _connection_return_code_v5
{
    MQTT_CONNECTION_V5_REFUSED_UNSPECIFIED_ERR      = 0x80, ///< UNSPECIFIED ERROR (未定义错误)
    MQTT_CONNECTION_V5_REFUSED_MALFORMED_PKG        = 0x81, ///< MALFORMED PACKET (数据格式错误)
    MQTT_CONNECTION_V5_REFUSED_PROTOCOL_ERR         = 0x82, ///< PRTOCOL ERROR (协议错误)
    MQTT_CONNECTION_V5_REFUSED_IMPL_ERR             = 0x83, ///< IMPLEMENTATION SPECIFIC ERROR (存在服务器不支持的协议内容)
    MQTT_CONNECTION_V5_REFUSED_PVER                 = 0x84, ///< UNSUPPORTED PROTOCOL VERSION (不支持的协议版本)
    MQTT_CONNECTION_V5_REFUSED_CID                  = 0x85, ///< CLIENT IDENTIFIER NOT VALID (客户端标识被拒)
    MQTT_CONNECTION_V5_REFUSED_ACCOUNT              = 0x86, ///< BAD USER NAME OR PASSWORD (用户名或密码错误)
    MQTT_CONNECTION_V5_REFUSED_NOT_AUTHED           = 0x87, ///< NOT AUTHORIZED (未鉴权/无鉴权信息)
    MQTT_CONNECTION_V5_REFUSED_BAD_SVR              = 0x88, ///< SERVER UNAVAILABLE (服务器不可用)
    MQTT_CONNECTION_V5_REFUSED_SVR_BUSY             = 0x89, ///< SERVER BUSY (服务器繁忙，稍后重试)
    MQTT_CONNECTION_V5_REFUSED_BANNED               = 0x8A, ///< BANNED (被服务器禁止接入，黑名单)
    MQTT_CONNECTION_V5_REFUSED_BAD_AUTH_METHOD      = 0x8C, ///< BAD AUTHENTICATION METHOD (无效/不支持的鉴权方式)
    MQTT_CONNECTION_V5_REFUSED_TOPIC_NAME_INVAL     = 0x90, ///< TOPIC NAME INVALID (本服务器不接受此遗嘱话题)
    MQTT_CONNECTION_V5_REFUSED_PKG_TOO_LARGE        = 0x95, ///< PACKET TOO LARGE (报文超允许大小)
    MQTT_CONNECTION_V5_REFUSED_QUOTA_EXCEEDED       = 0x97, ///< QUOTA EXCEEDED (超额)
    MQTT_CONNECTION_V5_REFUSED_PAYLOAD_INVAL        = 0x99, ///< PAYLOAD FORMAT INVALID (遗嘱消息载荷格式不符合pfi所指示格式)
    MQTT_CONNECTION_V5_REFUSED_RETAIN_NOT_SUPPORTED = 0x9A, ///< RETAIN NOT SUPPORTED (服务器不支持置顶/保持消息特性，但will retain置了1)
    MQTT_CONNECTION_V5_REFUSED_QOS_NOT_SUPPORTED    = 0x9B, ///< QoS NOT SUPPORTED (服务器不支持遗嘱消息指定QoS)
    MQTT_CONNECTION_V5_REFUSED_USE_ANOTHER_SVR      = 0x9C, ///< USE ANOTHER SERVER (服务器暂时不可用，客户端需要临时使用其他服务器)
    MQTT_CONNECTION_V5_REFUSED_SVR_MOVED            = 0x9D, ///< SERVER MOVED (服务器永久迁移，客户端需要使用其他服务器)
    MQTT_CONNECTION_V5_REFUSED_RATE_EXCEEDED        = 0x9F, ///< CONNECTION RATE EXCEEDED (频繁连接)
    MQTT_CONNECTION_CODE_MAX                        = 0xff,
}mqtt_connack_code_v5_e;

typedef enum _disconnect_reason_code
{
    MQTT_DISCONNECT_RC_NORMAL                       = 0x00, ///< 正常断开，且不触发Will Message
    MQTT_DISCONNECT_RC_WITH_WILL_MSG                = 0x04, ///< 正常断开，依旧触发Will Message
    MQTT_DISCONNECT_RC_UNSPECIFIED_ERR              = 0x80, ///< UNSPECIFIED ERROR (未定义错误)
    MQTT_DISCONNECT_RC_MALFORMED_PKG                = 0x81, ///< MALFORMED PACKET (数据格式错误)
    MQTT_DISCONNECT_RC_PROTOCOL_ERR                 = 0x82, ///< PRTOCOL ERROR (协议错误)
    MQTT_DISCONNECT_RC_IMPL_ERR                     = 0x83, ///< IMPLEMENTATION SPECIFIC ERROR (存在服务器不支持的协议内容)
    MQTT_DISCONNECT_RC_NOT_AUTHED                   = 0x87, ///< NOT AUTHORIZED (未鉴权/无鉴权信息)
    MQTT_DISCONNECT_RC_SVR_BUSY                     = 0x89, ///< SERVER BUSY (服务器繁忙，无法继续处理本客户端请求)
    MQTT_DISCONNECT_RC_SVR_SHUTTING_DOWN            = 0x8B, ///< SERVER SHUTTING DOWN (服务器关闭)
    MQTT_DISCONNECT_RC_KA_TIMEOUT                   = 0x8D, ///< KEEP ALIVE TIMEOUT (超过1.5倍KA时间没有保活)
    MQTT_DISCONNECT_RC_SESSION_TAKEN_OVER           = 0x8E, ///< ClientID冲突，本客户端被挤下线
    MQTT_DISCONNECT_RC_TOPIC_FILTER_INVALID         = 0x8F, ///< 订阅格式正确，但服务器不接受
    MQTT_DISCONNECT_RC_TOPIC_NAME_INVALID           = 0x90, ///< 发布格式正常，但本端/对端不接受
    MQTT_DISCONNECT_RC_RECV_MAX_EXCEEDED            = 0x93, ///< 收到超过限制数的待响应(完成)的发布请求
    MQTT_DISCONNECT_RC_TOPIC_ALIAS_INVALID          = 0x94, ///< 发布信息的Alias超过协商限制值AliasMax
    MQTT_DISCONNECT_RC_PKG_TOO_LARGE                = 0x95, ///< 报文超允许大小
    MQTT_DISCONNECT_RC_MSG_RATE_TOO_HEIGH           = 0x96, ///< 消息频率过高
    MQTT_DISCONNECT_RC_QUOTA_EXCEEDED               = 0x97, ///< 超额
    MQTT_DISCONNECT_RC_ADMINISTRATIVE_ACTION        = 0x98, ///< 由于管理操作，连接关闭
    MQTT_DISCONNECT_RC_PAYLOAD_FMT_ERR              = 0x99, ///< 信息的载荷不符合指定格式
    MQTT_DISCONNECT_RC_RETAIN_NOT_SUPPORTED         = 0x9A, ///< 服务器不支持Retain
    MQTT_DISCONNECT_RC_QOS_NOT_SUPPORTED            = 0x9B, ///< 信息的QoS等级超过协商服务器允许值
    MQTT_DISCONNECT_RC_USE_ANOTHER_SVR              = 0x9C, ///< 服务器暂时不可用，客户端需要使用其他服务器(临时重定向)
    MQTT_DISCONNECT_RC_SVR_MOVED                    = 0x9D, ///< 服务器永久不可用，客户端需要使用其他服务器(永久重定向)
    MQTT_DISCONNECT_RC_SHARED_SUBSC_NOT_SUPPORTED   = 0x9E, ///< 不支持共享订阅特性，却请求了
    MQTT_DISCONNECT_RC_CONNECTION_RATE_EXCEEDED     = 0x9F, ///< 频繁连接
    MQTT_DISCONNECT_RC_MAX_CONNECT_TIME             = 0xA0, ///< 超过本连接允许使用最大时长
    MQTT_DISCONNECT_RC_SUBSC_ID_NOT_SUPPORTED       = 0xA1, ///< 不支持订阅ID特性，却请求了
    MQTT_DISCONNECT_RC_WILDCARD_SUBSC_NOT_SUPPORTED = 0xA2, ///< 不支持通配符订阅特性，却请求了
}mqtt_disconnect_reason_code_e;

typedef enum _subscribe_result
{
    MQTT_SUBSCRIBE_OK_WITH_QOS0             = 0x00,
    MQTT_SUBSCRIBE_OK_WITH_QOS1             = 0x01,
    MQTT_SUBSCRIBE_OK_WITH_QOS2             = 0x02,
    MQTT_SUBSCRIBE_ERR                      = 0x80,
    MQTT_SUBSCRIBE_ERR_IMPL                 = 0x83, ///< Implementation specific(订阅合规，但服务器不接受)
    MQTT_SUBSCRIBE_ERR_NOT_AUTH             = 0X87, ///< 本客户端无权订阅此话题
    MQTT_SUBSCRIBE_ERR_INVALID_FILTER       = 0x8F, ///< 话题格式正确，但不允许本客户端使用
    MQTT_SUBSCRIBE_ERR_PKG_ID_INUSE         = 0x91, ///< 消息ID重复
    MQTT_SUBSCRIBE_ERR_QUOTA_EXCEEDED       = 0x97, ///< 超额
    MQTT_SUBSCRIBE_ERR_SHARED_NOT_SUPPORT   = 0x9E, ///< 不支持本客户端使用【共享订阅】方式
    MQTT_SUBSCRIBE_ERR_SUBSC_ID_NOT_SUPPORT = 0xA1, ///< 服务器不支持【订阅ID】特性
    MQTT_SUBSCRIBE_ERR_WILDCARD_NOT_SUPPORT = 0xA2, ///< 服务器不支持【通配符订阅】
}mvs_mqtt_subscribe_result_e;

typedef enum _unsubscribe_result
{
    MQTT_UNSUBSCRIBE_OK                     = 0x00,
    MQTT_UNSUBSCRIBE_OK_WITH_NOT_EXISTED    = 0x11,
    MQTT_UNSUBSCRIBE_ERR                    = 0x80,
    MQTT_UNSUBSCRIBE_ERR_IMPL               = 0x83, ///< Implementation specific(订阅合规，但服务器不接受)
    MQTT_UNSUBSCRIBE_ERR_NOT_AUTH           = 0X87, ///< 本客户端无权订阅此话题
    MQTT_UNSUBSCRIBE_ERR_INVALID_FILTER     = 0x8F, ///< 话题格式正确，但不允许本客户端使用
    MQTT_UNSUBSCRIBE_ERR_PKG_ID_INUSE       = 0x91, ///< 消息ID重复
}mvs_mqtt_unsubscribe_result_e;

typedef enum _puback_reason_code
{
    MQTT_PUBACK_RC_SUCCESS                  = 0x00,
    MQTT_PUBACK_RC_NO_MATCH                 = 0x10, ///< 没有人订阅（属于成功发布）
    MQTT_PUBACK_RC_ERR                      = 0x80, ///< 通用失败（没有更准确的错误码）
    MQTT_PUBACK_RC_IMPL_ERR                 = 0x83, ///< 有效发布，但接收端不想接受
    MQTT_PUBACK_RC_NOT_AUTHED               = 0x87, ///< 无权发布此消息
    MQTT_PUBACK_RC_TOPIC_NAME_INVALID       = 0x90, ///< 格式正确，但本端不接受
    MQTT_PUBACK_RC_PKG_ID_IN_USE            = 0x91, ///< 报文ID正在使用（也就是异常PKG ID冲突)
    MQTT_PUBACK_RC_QUOTA_EXCEEDED           = 0x97, ///< 超额
    MQTT_PUBACK_RC_PAYLOAD_FMT_ERR          = 0x99, ///< 载荷格式错误
}puback_reason_code_e;
/***************************************************/
typedef enum _mqtt_message_properties_id
{
    MQTT_MPID_PFI               = 0x01, ///< PayloadFormatIndicator(PUBLISH, WILL)
    MQTT_MPID_MEI               = 0x02, ///< MessageExpiryInterval(PUBLISH, WILL)
    MQTT_MPID_CT                = 0x03, ///< ContentType(PUBLISH, WILL)
    MQTT_MPID_RSP_TOPIC         = 0x08, ///< ResponseTopic(PUBLISH, WILL)
    MQTT_MPID_CORR_DATA         = 0x09, ///< CorrelationData(PUBLISH, WILL)
    MQTT_MPID_SUBS_ID           = 0x0B, ///< SubscriptionIdentifier(PUBLISH, SUBSCRIBE)
    MQTT_MPID_SEI               = 0x11, ///< SessionExpiryInterval(CONNECT, CONNACK, DISCONNECT) 在CONNACK出现，表示CONNECT中的SEI没有被采纳
    MQTT_MPID_ACID              = 0x12, ///< AssignedClientIdentifier(CONNACK)
    MQTT_MPID_SVR_KA            = 0x13, ///< ServerKeepAlive(CONNACK)
    MQTT_MPID_AUTH_METHOD       = 0x15, ///< AuthenticationMethod(CONNECT, CONNACK, AUTH)
    MQTT_MPID_AUTH_DATA         = 0x16, ///< AuthenticationData(CONNECT, CONNACK, AUTH)
    MQTT_MPID_REQ_PROBLEM       = 0x17, ///< RequestProblemInformation(CONNECT)
    MQTT_MPID_WILL_DELAY        = 0x18, ///< WillDelayInterval(WILL)
    MQTT_MPID_REQ_RSP_INFO      = 0x19, ///< RequestResponseInformation(CONNECT)
    MQTT_MPID_RSP_INFO          = 0x1A, ///< ResponseInformation(CONNACK)
    MQTT_MPID_SVR_REF           = 0x1C, ///< ServerReference(CONNACK, DISCONNECT)
    MQTT_MPID_REASON            = 0x1F, ///< ReasonString(CONNACK, PUBACK, PUBREC, PUBREL, PUBCOMP, SUBACK, UNSUBACK, DISCONNECT, AUTH)
    MQTT_MPID_RECV_MAX          = 0x21, ///< ReceiveMaximum(CONNECT, CONNACK)
    MQTT_MPID_TOPIC_ALIAS_MAX   = 0x22, ///< TopicAliasMaximum(CONNECT, CONNACK)
    MQTT_MPID_TOPIC_ALIAS       = 0x23, ///< TopicAlias(PUBLISH)
    MQTT_MPID_MAX_QOS           = 0x24, ///< MaximumQoS(CONNACK)
    MQTT_MPID_RETAIN_AVA        = 0x25, ///< RetainAvailable(CONNACK)
    MQTT_MPID_USR_PROPERTY      = 0x26, ///< UserProperty(*)
    MQTT_MPID_MAX_PKG_SIZE      = 0x27, ///< MaximumPacketSize(CONNECT, CONNACK)
    MQTT_MPID_WILDCARD_SUBS_AVA = 0x28, ///< WildcardSubscriptionAvailable(CONNACK)
    MQTT_MPID_SUBS_ID_AVA       = 0x29, ///< SubscriptionIdentifierAvailable(CONNACK)
    MQTT_MPID_SHARED_SUBS_AVA   = 0x2A, ///< SharedSubscriptionAvailable(CONNACK)

    MQTT_MPID_MAX,
}mvs_mqtt_mprops_id_e;

typedef struct _mqtt_message_payload_template
{
    union { ///< 指示了不同场景和设置下会有不同要求/限制数据内容格式，仅此而已
        mv_u8ptr_t pu8_utf8_str;  ///< 字符串内容(UTF-8 Encoding)
        mv_u8ptr_t pu8_datas;     ///< 数据内容
    };
    mv_u16_t       u16_len;       ///< 字符串长度
}mvs_mqtt_mplt_t;

typedef struct _mqtt_message_large_payload_template
{
    union { ///< 指示了不同场景和设置下会有不同要求/限制数据内容格式，仅此而已
        mv_u8ptr_t pu8_utf8_str;  ///< 字符串内容(UTF-8 Encoding)
        mv_u8ptr_t pu8_datas;     ///< 数据内容
    };
    mv_u32_t       u32_len;       ///< 字符串长度
}mvs_mqtt_mlplt_t;

typedef struct _mqtt_message_pair
{
    mvs_mqtt_mplt_t name;
    mvs_mqtt_mplt_t value;
    struct _mqtt_message_pair *next;
}mvs_mqtt_mpair_t;

typedef struct _mqtt_topic_attr
{
    union {
        union {
            struct {
#if ( __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ )
                mv_u8_t u2_reserve:2;         ///< 保留（必须为0）
                mv_u8_t u2_retain_handling:2; ///< 订阅RETAIN状态消息时下发动作（0=马上下发；1=未曾订阅时下发；2=不下发）
                mv_u8_t u1_rap:1;             ///< 是否强制此TOPIC的PUBLISH消息到本客户端时retain值为0（0=强制为0；1=不改变）
                mv_u8_t u1_no_local:1;        ///< 禁用消息回环(0=允许回环；1=禁用回环)
                mv_u8_t u2_max_qos:2;         ///< 此TOPIC的PUBLISH消息到本客户端最大QoS限制(0,1,2)
#else
                mv_u8_t u2_max_qos:2;         ///< 此TOPIC的PUBLISH消息到本客户端最大QoS限制(0,1,2)
                mv_u8_t u1_no_local:1;        ///< 禁用消息回环(0=允许回环；1=禁用回环)
                mv_u8_t u1_rap:1;             ///< 是否强制此TOPIC的PUBLISH消息到本客户端时retain值为0（0=强制为0；1=不改变）
                mv_u8_t u2_retain_handling:2; ///< 订阅RETAIN状态消息时下发动作（0=马上下发；1=未曾订阅时下发；2=不下发）
                mv_u8_t u2_reserve:2;         ///< 保留（必须为0）
#endif
            };
            mv_u8_t u8_subsc_flags;
        }subscribe;
        struct {
            mv_u8_t u2_qos_level:2;           ///< 质量服务等级(0=无需响应；1=重复直到有响应；2=保证不重复但等待响应)
            mv_u8_t u1_retain:1;              ///< 消息保持(置顶)
            mv_u8_t u5_reserve:5;             ///< 保留（必须为0）
        }call;
    }u;
    mv_u8_t     u8_retry;      ///< =0则强制QoS为0；>0则QoS>0时有效；！！！注意每一次retry内部都会对timeout进行适当延长，以减少低带宽延时导致的频繁重试
}mvs_mqtt_tpat_t;

/**
 * @brief 消息属性（V5以上版本支持）
 * 
 */
typedef struct _mqtt_message_properties
{
    mv_u8_t           u8_pfi;                       ///< (0x01)载荷格式(PaloadFormatIndicator, 0=无格式（其他标记utf8参数均不强制utf8编码），1=UTF8（默认）)
    mv_u32_t          u32_mei;                      ///< (0x02)消息过期时间(MessageExpiryInterval)
    mvs_mqtt_mplt_t   content_type;                 ///< (0x03)内容类型(ContentType UTF-8；客户端应用级定义；可以自定义一些实际应用场景的消息(0x03)内容类型定义)
    mvs_mqtt_mplt_t   rsp_topic;                    ///< (0x08)响应话题(ResponseTopic UTF-8；用于订阅端收到此消息时，发送PUBLISH给指定的topic)
    mvs_mqtt_mplt_t   corr_data;                    ///< (0x09)相关数据(CorrelationData RAW；客户端应用级自定义数据内容)
    mv_s32_t          s32_subsc_id;                 ///< (0x0B)订阅标识符(SubscriptionIdentifier；有效值1到268,435,455)
    mv_u32_t          u32_sei;                      ///< (0x11)对话过期时间(SessionExpiryInterval；0=不保留,0xffffffff=永久,else=保留时长秒)
    mvs_mqtt_mplt_t   acid;                         ///< (0x12)自动分配ClientID(AssignedClientIdentifier；当ClientID为0长时，可由服务器自动分配ClientID，可以一直使用直到会话过期)
    mv_u16_t          u16_svr_keepalive;            ///< (0x13)服务器保活时间((0x13)ServerKeepAlive；当服务器返回时，必须以此值为准替代当前Keepalive时间)
    mvs_mqtt_mplt_t   auth_method;                  ///< (0x15)鉴权方式(AuthenticationMethod UTF-8；用于【增强鉴权】流程协商鉴权方式)
    mvs_mqtt_mplt_t   auth_data;                    ///< (0x16)鉴权数据(AuthenticationMethod RAW；用于【增强鉴权】流程携带鉴权数据内容)
    mv_u8_t           u8_req_problem;               ///< (0x17)请求异常信息(RequestProblemInformation；0=仅能在PUBLISH/CONNACK/DISCONNECT携带异常信息；1=任意报文类型均可携带异常信息)
    mv_u32_t          u32_will_delay;               ///< (0x18)遗言消息延迟发送时间(WillDelayInterval)
    mv_u8_t           u8_req_rsp_info;              ///< (0x19)请求响应详情(RequestResponseInformation；0=必定不要；1=请求携带)
    mvs_mqtt_mplt_t   rsp_information;              ///< (0x1A)响应详情(ResponseInformation UTF-8)
    mvs_mqtt_mplt_t   svr_ref;                      ///< (0x1C)相关服务器(ServerReference UTF-8；一般可用于重定向)
    mvs_mqtt_mplt_t   reason_string;                ///< (0x1F)原因(ReasonString UTF-8；受u8_req_problem控制，一般异常时抛出)
    mv_u16_t          u16_recv_max;                 ///< (0x21)最大接收次数(ReceiveMaximum)；用于限制QoS=1/2的最大重试发送次数
    mv_u16_t          u16_topic_alias_max;          ///< (0x22)最大主题别名数(TopicAliasMaximum；0=不接受别名设置; FIXME: 当前实现当订阅了通配topic时，alias实现不完善，此时请勿使用，后续优化)
    mv_u16_t          u16_topic_alias;              ///< (0x23)当前主题别名(TopicAlias；0=无效)
    mv_u8_t           u8_maximum_qos;               ///< (0x24)最大支持QoS等级(Maximum QoS)
    mv_u8_t           u8_retain_available;          ///< (0x25)是否支持置顶/保持消息(RetainAvailable)
    mvs_mqtt_mpair_t *usr_props_pairs;              ///< (0x26)用户属性对列表
    mv_u32_t          u32_pkg_size_max;             ///< (0x27)最大包长(MaximumPacketSize)
    mv_u8_t           u8_wildcard_subs_ava;         ///< (0x28)通配符订阅支持(WildcardSubscriptionAvailable)
    mv_u8_t           u8_subs_id_ava;               ///< (0x29)订阅话题ID支持(SubscriptionIdentifierAvailable)
    mv_u8_t           u8_shared_subs_ava;           ///< (0x2a)共享订阅支持(SharedSubscriptionAvailable；订阅topic样式为 $share/{ShareName}/{filter})

    mv_u8_t           au8_mpid_mask[MQTT_MPID_MAX]; ///< 属性选项列表(根据对应位进行数据挑选参与格式化)
}mvs_mqtt_mprop_t;

typedef mv_s32_t(*pf_mqtt_in_msg_call)(mv_vptr_t phdl, mv_vptr_t pattr); ///< (mvs_mqtt_msg_attr_t *pattr)
typedef struct _mqtt_subscribe_topic_template
{
    mvs_mqtt_mplt_t     topic;  ///< 话题(可以使用订阅用通配符'#'进行多级通配订阅或'+'进行一级通配订阅)
    mvs_mqtt_tpat_t     attr;   ///< 话题特性
    pf_mqtt_in_msg_call f_call; ///< 话题消息处理回调（仅SUBSCRIBE)，NULL则通用回调f_publish_resolve
}mvs_mqtt_subplt_t;
/**
 * @brief 消息请求的特性参数
 * 
 */
typedef struct _mqtt_msg_attr
{
    mvs_mqtt_mprop_t           props;                ///< 消息属性
    union {
        struct {
            mvs_mqtt_mplt_t    client_id;            ///< 客户端标识
            mvs_mqtt_tpat_t    will_attr;            ///< 遗嘱话题特性
            mvs_mqtt_mplt_t    will_topic;           ///< 遗嘱话题(存在则启用LWT)
            mvs_mqtt_mplt_t    will_msg;             ///< 遗嘱消息体
            mvs_mqtt_mplt_t    user_name;            ///< 连接用户名
            mvs_mqtt_mplt_t    password;             ///< 连接密码(用户名不存在时，无效)
            mv_u16_t           u16_keepalive;        ///< 维持机制最大间隔（秒；0表示关闭此机制）
            mv_u8_t            u8_clean_session;     ///< 全新连接（清空曾订阅话题）
            mv_u8_t            u8_session_unwilling; ///< 当获得session状态与clean session预期不一致时的动作；(0=断开连接；1=继续使用)
            mv_u8_t            u8_pver;              ///< MQTT协议版本（默认为MQTT_PROTOCOL_V3_1_1）
            mv_u8_t            u8_bc;                ///< 协议向下兼容（用于个别服务器对V5的响应出现V3格式情况，开启则允许，默认严格匹配）
        }connect;
        struct {
            mvs_mqtt_tpat_t    attr;                 ///< 发布特性
            mvs_mqtt_mplt_t    topic;                ///< 话题(注意不要包含订阅用通配符'#'或'+')
            mvs_mqtt_mlplt_t   msg;                  ///< 消息体
        }publish;
        struct {
            /** QoS必定为1 */
            mv_u32_t           u32_topic_num;        ///< 订阅话题数
            mvs_mqtt_tpat_t    attr;                 ///< 订阅特性(订阅QoS内部固定为1,所以这里只有重试次数retry有效)
            mvs_mqtt_subplt_t *plist;                ///< 订阅列表
        }subscribe;
        struct {
            /** QoS必定为1 */
            mv_u32_t           u32_topic_num;        ///< 取消订阅话题数
            mvs_mqtt_subplt_t *plist;                ///< 取消订阅列表
        }unsubscribe;
        struct {
            mv_u8_t            u8_reason_code;       ///< 主动断开原因[]
        }disconnect;
    }u;
}mvs_mqtt_msg_attr_t;

typedef struct _mqtt_msg_ack
{
    mvs_mqtt_mprop_t           props;                ///< 响应消息属性
    union {
        struct {
            mv_u8_t            u8_ack_status;        ///< 连接结果[mvs_mqtt_connect_result_e]
            mv_u8_t            u8_return_code;       ///< 连接结果描述[mqtt_connack_code_v3_e / mqtt_connack_code_v5_e]
        }connack;
        struct {
            mv_u8_t            u8_reason_code;       ///< QoS1/2的发布结果码[puback_reason_code_e]
        }puback;
        struct {
            mv_u8ptr_t         pu8_ack_code_list;    ///< 订阅结果列表[mvs_mqtt_subscribe_result_e]；按顺序对应请求的订阅列表每一项
        }suback;
        struct {
            mv_u8ptr_t         pu8_ack_code_list;    ///< 取消订阅结果列表[mvs_mqtt_unsubscribe_result_e]；按顺序对应请求的取消订阅列表每一项
        }unsuback;
    }u;
}mvs_mqtt_msg_ack_t; /** 注意响应资源释放 */

/******************************************/
typedef mv_s32_t(*pf_publish_resolve)(mv_vptr_t phdl, mvs_mqtt_msg_attr_t *pattr);
typedef mv_s32_t(*pf_disconnected)(mv_vptr_t phdl, mvs_mqtt_msg_attr_t *pattr);
typedef mv_s32_t(*pf_connection_error)(mv_vptr_t phdl);
typedef mv_s32_t(*pf_tunnel_connect)(mv_vptr_t phdl, mv_s32_t s32_timeout_msec);
typedef mv_s32_t(*pf_tunnel_disconnect)(mv_vptr_t phdl);
typedef mv_s32_t(*pf_tunnel_data_send)(mv_vptr_t phdl, mv_cvptr_t cp_data, mv_s32_t s32_len, mv_s32_t s32_timeout_msec);
typedef mv_s32_t(*pf_tunnel_data_recv)(mv_vptr_t phdl, mv_vptr_t   p_data, mv_s32_t s32_len, mv_s32_t s32_timeout_msec);
typedef struct _mqtt_module_handle
{
    mv_vptr_t            phdl_core;            ///< 模块核心句柄(调用init时初始化)
    /*************************************/
    pf_publish_resolve   f_publish_resolve;    ///< 下发消息处理回调
    pf_connection_error  f_conn_err;           ///< 连接异常通知回调（注意不能在回调中调用disconnect或connect接口）
    pf_disconnected      f_disconnected;       ///< 连接被动断开回调（注意不能在回调中调用disconnect或connect接口）
    mv_s32_t             s32_global_timeout_ms;///< 通信全局超时时间
    pf_tunnel_connect    f_tunnel_connect;     ///< 通信通道连接回调
    pf_tunnel_disconnect f_tunnel_disconnect;  ///< 通信通道断开回调
    pf_tunnel_data_send  f_turnnel_data_send;  ///< 通信通道数据发送
    pf_tunnel_data_recv  f_turnnel_data_recv;  ///< 通信通道数据接收
    mv_vptr_t            phdl_log;             ///< mvt log模块句柄
    mv_u8_t              u8_log_region;        ///< mvt log句柄使用区域
    mv_u8_t              au8_reserve[3];       ///< (对齐保留）
    mv_vptr_t            p_usr_data;           ///< 用户自定义数据
    mv_s32_t             s32_ext_len;          ///< 用户自定义变长数据长度
    mv_u8_t              au8_ext_data[1];      ///< 用户自定义变长结构数据
}mvs_mqtt_mhdl_t;

mv_s32_t mvs_mqtt_init(mvs_mqtt_mhdl_t *phdl, mv_s32_t s32_max_msgs);

mv_s32_t mvs_mqtt_uninit(mvs_mqtt_mhdl_t *phdl);

/** 注意：connect在上一次被动disconnect情况下，可自动释放原有资源（无需单独调用disconnect），重新connect */
mv_s32_t mvs_mqtt_connect(mvs_mqtt_mhdl_t *phdl, mvs_mqtt_msg_attr_t *pattr, mvs_mqtt_mprop_t *pwill_props, mvs_mqtt_msg_ack_t *pack, mv_s32_t s32_timeout_ms);

mv_s32_t mvs_mqtt_disconnect(mvs_mqtt_mhdl_t *phdl, mvs_mqtt_msg_attr_t *pattr);

/** 返回MV_EC_UNREACHABLE时，证明reason code != 0，可以根据V5的reason code进行应用级进一步细分判断处理 */
mv_s32_t mvs_mqtt_publish(mvs_mqtt_mhdl_t *phdl, mvs_mqtt_msg_attr_t *pattr, mvs_mqtt_msg_ack_t *pack, mv_s32_t s32_timeout_ms);

mv_s32_t mvs_mqtt_subscribe(mvs_mqtt_mhdl_t *phdl, mvs_mqtt_msg_attr_t *pattr, mvs_mqtt_msg_ack_t *pack, mv_s32_t s32_timeout_ms);

mv_s32_t mvs_mqtt_unsubscribe(mvs_mqtt_mhdl_t *phdl, mvs_mqtt_msg_attr_t *pattr, mvs_mqtt_msg_ack_t *pack, mv_s32_t s32_timeout_ms);

/**
 * @brief 释放properties内存资源
 * 
 * @param p_props [in] 待释放properties结构引用
 * @return \
 * 
 * @note 一般用于释放ack返回提取出的properties内存资源
 */
mv_void_t mvs_mqtt_msg_properties_release(mvs_mqtt_mprop_t *p_props);
/**
 * @brief 调试接口，打印props结构所有有效成员数据内容
 * 
 * @param p_props [in] 待打印properties结构引用
 * @return \
 */
mv_void_t mvs_mqtt_msg_properties_dump(mvs_mqtt_mprop_t *p_props);

MVCXX_EXTERN_END

#endif
